package com.h2cloud.aspect;

import com.h2cloud.depends.JsonUtil;
import com.h2cloud.depends.NetworkUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * 切面基础类
 * 一些公共方法
 */
@Slf4j
public abstract class BaseAspect {

    private static final String REPLACE_PREFIX = "com.bj58.ehr.corehr.";

    /**
     * 获取切面方法上包含的指定注解
     *
     * @param joinPoint
     * @param annotationClass
     * @param <T>
     * @return
     */
    public <T extends Annotation> T getAnnotation(JoinPoint joinPoint, Class<T> annotationClass) {
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Method[] methods = joinPoint.getSignature().getDeclaringType().getMethods();
        for (Method m : methods) {
            if (m.getName().equals(methodName)) {
                if (m.getParameterTypes().length == arguments.length) {
                    T annotation = m.getAnnotation(annotationClass);
                    return annotation;
                }
            }
        }
        return null;
    }

    /**
     * 默认key策略
     *
     * @param targetName
     * @param methodName
     * @param arguments
     * @return
     */
    public static String getCacheKey(String key, String targetName, String methodName,
                                     Object[] arguments) {
        StringBuffer sb = new StringBuffer();
        if (StringUtils.isNotBlank(key)) {
            sb.append(key);
        } else {
            sb.append(targetName).append(".").append(methodName);
        }
        if (arguments != null && (arguments.length != 0)) {
            sb.append("#").append(JsonUtil.toJson(arguments));
        }
//        return sb.toString();
        return sb.toString().replace("[", "").replace("\"", "").replace("]", "").replace(REPLACE_PREFIX, "");
    }

    /**
     * 获取key
     *
     * @param key
     * @param arguments
     * @return
     */
    public static String getCacheKey(String key, Object[] arguments) {
        StringBuffer sb = new StringBuffer();
        sb.append(key);
        if (arguments != null && (arguments.length != 0)) {
            sb.append("#").append(JsonUtil.toJson(arguments));
        }
        return sb.toString().replace("[", "").replace("\"", "").replace("]", "").replace(REPLACE_PREFIX, "");
    }

    public static Object[] getArgStr(Object[] arguments, String[] paramNames, Signature signature) {
        System.out.println("Arrays.toString(paramNames) = " + Arrays.toString(paramNames));
        if (paramNames == null || paramNames.length == 0) {
            return arguments;
        }
        //自定义参数方式
        MethodSignature methodSignature = (MethodSignature) signature;
        String[] parameterNames = methodSignature.getParameterNames();
        // 通过map封装参数和参数值
        HashMap<String, Object> paramMap = new HashMap<>();
        //遍历参数
        for (int i = 0; i < parameterNames.length; i++) {
            paramMap.put(parameterNames[i], arguments[i]);
            System.out.println("name:" + parameterNames[i] + " value:" + arguments[i]);
        }

        List<Object> customArgs = new ArrayList<>();
        for (String s : paramNames) {
            if (s.contains("#")) {
                //获取下一层多个参数（下级只可一层） A#b1#b2#b3
                String[] innerParams = s.split("#");
                //innerParams[0] ClassName
                //innerParams[1][2]... InnerClassParameters
                if (innerParams[0] != null && innerParams[1] != null) {
                    Object currentObject = paramMap.get(innerParams[0]);
                    if (currentObject == null) {
                        customArgs.add(null);
                        continue;
                    }

                    // 遍历反射对象内参数
                    for (int childParamIndex = 1; childParamIndex < innerParams.length; childParamIndex++) {
                        try {
                            Field field = currentObject.getClass().getDeclaredField(innerParams[childParamIndex]);
                            field.setAccessible(true);
                            try {
                                Object o = field.get(currentObject);
                                customArgs.add(o);
                            } catch (IllegalAccessException e) {
                                log.info("{} Field对象强制转换后 底层{}字段不可访问。", innerParams[0], field.getName(), e);
                                e.printStackTrace();
                            }
                        } catch (NoSuchFieldException e) {
                            e.printStackTrace();
                        }
                    }
                }

            } else if (s.contains(".")) {
                //迭代获取下层参数（最终参数只可一个） A.b3.c5.d2
                String[] innerParams = s.split("\\.");
                //innerParams[0] ClassName
                //innerParams[1] NextLayerClassName
                //innerParams[2] NextNextLayerClassName
                Object currentObject = paramMap.get(innerParams[0]);
                if (currentObject == null) {
                    customArgs.add(null);
                    continue;
                }

                //遍历反射对象内参数
                Field field = null;
                for (int childParamIndex = 1; childParamIndex < innerParams.length; childParamIndex++) {
                    try {
                        field = currentObject.getClass().getDeclaredField(innerParams[childParamIndex]);
                        field.setAccessible(true);
                        try {
                            currentObject = field.get(currentObject);
                            if (currentObject == null) {
                                log.info("@Lock 参数为:{}, 其中 {}字段为空，设置默认值 null", s, innerParams[childParamIndex]);
                                customArgs.add(null);
                                break;
                            }
                        } catch (IllegalAccessException e) {
                            log.info("{} Field对象强制转换后 底层{}字段不可访问, error:{}", currentObject.getClass().getName(), innerParams[childParamIndex], e);
                            customArgs.add(null);
                            break;
                        }

                    } catch (NoSuchFieldException e) {
                        log.info("@Lock 参数为:{}, 其中 {}字段不存在，设置默认值 null, error:{}", s, innerParams[childParamIndex], e);
                        customArgs.add(null);
                        break;
                    }

                    if (childParamIndex == innerParams.length - 1) {
                        customArgs.add(currentObject);
                    }

                }

            } else {
                customArgs.add(paramMap.get(s));
            }
        }
        return customArgs.toArray();
    }


    /**
     * 获取分布式锁的request id
     *
     * @return 分布式锁的request id
     * @throws SocketException 异常
     */
    public static String getLockRequestId() throws SocketException {
        String ip = NetworkUtil.getLocalIpList();
        long threadId = Thread.currentThread().getId();
        return ip + "#" + threadId;
    }

}
